package com.zzjx.web.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.redxun.common.annotation.MethodDefine;
import com.redxun.common.annotation.ParamDefine;
import com.redxun.common.annotation.TenantNotSupport;
import com.redxun.common.base.db.BaseService;
import com.redxun.common.base.entity.BaseEntity;
import com.redxun.common.base.entity.JsonPageResult;
import com.redxun.common.base.entity.JsonResult;
import com.redxun.common.base.entity.QueryData;
import com.redxun.common.base.search.QueryFilter;
import com.redxun.common.base.search.QueryFilterBuilder;
import com.redxun.common.constant.HttpMethodConstants;
import com.redxun.common.tool.BeanUtil;
import com.redxun.common.tool.StringUtils;
import com.redxun.common.utils.ContextUtil;
import com.redxun.common.utils.ExceptionUtil;
import com.redxun.log.annotation.AuditLog;
import com.redxun.log.model.Audit;
import com.redxun.log.model.LogContext;
import com.redxun.log.util.EntityUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;

/**
 * 模块：zpaas
 * 包名：com.zzjx.web.controller
 * 功能描述：提供控制器一些基础方法，如获得i18n国际化的方法等
 *
 * @author：csx
 * @date:2019/2/21
 */
@Api("BaseController")
@RestController
public abstract class BaseController<E extends BaseEntity<? extends Serializable>> {
    protected Logger logger = LoggerFactory.getLogger(BaseController.class);

    /**
     * 返回缺省的语言编码对应的文字描述
     *
     * @param key 字符编码
     * @return
     */
    public String getMessage(String key) {
        return "";
    }

    /**
     * 返回编码对应的文字内容
     *
     * @param key   字符编码
     * @param local 语言区域编码
     * @return
     */
    public String getMessage(String key, String local) {
        return "";
    }

    /**
     * @return
     */
    public abstract BaseService<E> getBaseService();

    /**
     * 获取注释。
     *
     * @return
     */
    public abstract String getComment();

    /**
     * 子类可以添加对这个过滤器添加条件。
     *
     * @param filter
     */
    protected void handleFilter(QueryFilter filter) {
        TenantNotSupport annotation = this.getClass().getAnnotation(TenantNotSupport.class);
        if (annotation != null) {
            return;
        }
        String tenantId = ContextUtil.getCurrentTenantId();
        if (StringUtils.isNotEmpty(tenantId)) {
            filter.addQueryParam("Q_TENANT_ID__S_EQ", tenantId);
        }
    }

    /**
     * 返回当前上下文的租户ID
     *
     * @return
     */
    protected String getCurrentTenantId() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String tenantId = request.getParameter("tenantId");
        if (StringUtils.isEmpty(tenantId)) {
            tenantId = ContextUtil.getCurrentTenantId();
        }
        return tenantId;
    }

    /**
     * 子类可以增加这个过滤器处理数据
     *
     * @param page
     */
    protected void handlePage(IPage page) {

    }

    /**
     * 子类可以增加这个过滤器处理数据
     *
     * @param ent
     */
    protected void handleData(E ent) {

    }

    protected JsonResult beforeSave(E ent) {
        return JsonResult.Success();
    }

    protected JsonResult beforeRemove(List<String> list) {
        return JsonResult.Success();
    }

    @Resource
    protected HttpServletRequest request;

    @MethodDefine(title = "根据实体Id删除业务行信息", path = "/del", method = HttpMethodConstants.POST,
            params = {@ParamDefine(title = "实体ID", varName = "ids")})
    @ApiOperation(value = "删除业务行数据", notes = "根据实体Id删除业务行信息,parameters is {ids:'1,2'}")
    @AuditLog(operation = "删除业务行数据")
    @PostMapping("del")
    public JsonResult del(@RequestParam String ids) {

        if (StringUtils.isEmpty(ids)) {
            return new JsonResult(false, "");
        }
        String[] aryId = ids.split(",");
        List list = Arrays.asList(aryId);

        JsonResult rtn = beforeRemove(list);
        if (!rtn.isSuccess()) {
            return rtn;
        }


        JsonResult result = JsonResult.getSuccessResult("删除" + getComment() + "成功!");

        LogContext.put(Audit.OPERATION, "删除" + getComment());

        String detail = "";

        LogContext.put(Audit.ACTION, Audit.ACTION_DEL);

        for (Object id : list) {
            String idStr = id.toString();
            E ent = getBaseService().get(idStr);
            String fieldInfo = EntityUtil.getInfo(ent, false);
            detail += fieldInfo + "\r\n";
        }
        LogContext.put(Audit.DETAIL, detail);

        getBaseService().delete(list);
        return result;
    }

    @MethodDefine(title = "查询当前业务表的所有数据", path = "/getAll", method = HttpMethodConstants.GET,
            params = {})
    @ApiOperation(value = "查询当前业务表的所有数据", notes = "查询当前实体表的所有数据。")
    @GetMapping("getAll")
    public JsonPageResult getAll() throws Exception {
        List data = getBaseService().getAll();
        JsonPageResult result = new JsonPageResult();
        result.setData(data);
        result.setShow(false);
        return result;
    }

    @MethodDefine(title = "保存业务数据记录", path = "/save", method = HttpMethodConstants.POST,
            params = {@ParamDefine(title = "实体数据JSON", varName = "entity")})
    @ApiOperation(value = "保存业务数据记录", notes = "根据提交的业务JSON数据保存业务数据记录")
    @AuditLog(operation = "保存业务数据记录")
    @PostMapping("/save")
    public JsonResult save(@Validated @ApiParam @RequestBody E entity, BindingResult validResult) throws Exception {
        JsonResult result = handValid(validResult);
        if (!result.isSuccess()) {
            return result;
        }

        Serializable pkId = entity.getPkId();
        String str = "";
        String operation = "";
        try {
            result = beforeSave(entity);
            if (!result.isSuccess()) {
                return result;
            }
            if (BeanUtil.isEmpty(pkId)) {
                String fieldInfo = "添加" + getComment() + ":" + EntityUtil.getInfo(entity, true);

                getBaseService().insert(entity);
                //处理日志相关。
                LogContext.put(Audit.PK, entity.getPkId());
                LogContext.put(Audit.ACTION, Audit.ACTION_ADD);
                LogContext.put(Audit.DETAIL, fieldInfo);

                str = "添加" + getComment() + "成功";
                operation = "添加" + getComment();

                LogContext.put(Audit.OPERATION, operation);
            } else {
                E oldEnt = getBaseService().get(pkId);

                //处理日志相关。
                String fieldInfo = EntityUtil.getUpdInfo(oldEnt, entity);
                LogContext.put(Audit.ACTION, Audit.ACTION_UPD);
                LogContext.put(Audit.PK, pkId);
                LogContext.put(Audit.DETAIL, "更新" + getComment() + ":" + fieldInfo);

                getBaseService().update(entity);
                str = "更新" + getComment() + "成功";

                operation = "更新" + getComment();

                LogContext.put(Audit.OPERATION, operation);
            }
            result = JsonResult.getSuccessResult(str);
            result.setData(entity);
        } catch (Exception ex) {
            String errMsg = ExceptionUtil.getExceptionMessage(ex);

            if (BeanUtil.isEmpty(pkId)) {
                str = "添加" + getComment() + "失败!";
            } else {
                str = "更新" + getComment() + "失败!";
            }
            //处理日志相关。
            LogContext.put(Audit.OPERATION, operation);
            LogContext.put(Audit.DETAIL, errMsg);

            result = JsonResult.getFailResult(str);
            result.setData(errMsg);
        }
        return result;
    }

    /**
     * 检查数据是否合法
     *
     * @param validResult
     * @return
     */
    private JsonResult handValid(BindingResult validResult) {
        if (!validResult.hasErrors()) {
            return JsonResult.Success();
        }
        JsonResult result = JsonResult.Fail("表单验证失败");
        List<ObjectError> allErrors = validResult.getAllErrors();
        StringBuilder sb = new StringBuilder();
        for (ObjectError error : allErrors) {
            if (error instanceof FieldError) {
                sb.append("[" + ((FieldError) error).getField() + "]");
            }
            sb.append(error.getDefaultMessage());
            sb.append("\r\n");
        }
        result.setData(sb.toString());

        return result;

    }

    /**
     * 获得所有查询数据列表，不传入条件时，则返回所有的记录
     *
     * @return
     * @throws Exception
     */
    @MethodDefine(title = "根据条件查询业务数据记录", path = "/query", method = HttpMethodConstants.POST,
            params = {@ParamDefine(title = "查询条件", varName = "queryData")})
    @ApiOperation(value = "根据条件查询业务数据记录", notes = "根据条件查询业务数据记录")
    @PostMapping(value = "/query")
    public JsonPageResult query(@RequestBody QueryData queryData) throws Exception {
        JsonPageResult jsonResult = JsonPageResult.getSuccess("返回数据成功!");
        try {
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = servletRequestAttributes.getRequest();
            String url = request.getRequestURI();

            long start = System.currentTimeMillis();
            QueryFilter filter = QueryFilterBuilder.createQueryFilter(queryData);
            handleFilter(filter);
            IPage page = getBaseService().query(filter);
            handlePage(page);
            jsonResult.setPageData(page);

            logger.info("url:" + url + ",escape time:" + (System.currentTimeMillis() - start) + "ms");


        } catch (Exception ex) {
            jsonResult.setSuccess(false);
            logger.error(ExceptionUtil.getExceptionMessage(ex));
            jsonResult.setMessage(ExceptionUtil.getExceptionMessage(ex));
        }
        return jsonResult;
    }

    /**
     * 根据主键查询记录详细信息
     *
     * @param pkId
     * @return
     */
    @MethodDefine(title = "根据主键查询业务数据详细信息", path = "/get", method = HttpMethodConstants.GET,
            params = {@ParamDefine(title = "主键", varName = "pkId")})
    @ApiOperation(value = "根据主键查询业务数据详细信息", notes = "根据主键查询业务数据详细信息")
    @GetMapping("/get")
    public JsonResult<E> get(@RequestParam(value = "pkId") String pkId) {
        JsonResult result = JsonResult.Success();
        result.setShow(false);
        if (ObjectUtils.isEmpty(pkId)) {
            return result.setData(new Object());
        }
        E ent = getBaseService().get(pkId);
        handleData(ent);
        return result.setData(ent);
    }

    @MethodDefine(title = "根据主键IDS查询业务数据详细信息", path = "/getByIds", method = HttpMethodConstants.GET,
            params = {@ParamDefine(title = "主键", varName = "ids")})
    @ApiOperation(value = "根据主键IDS查询业务数据详细信息", notes = "根据主键IDS查询业务数据详细信息")
    @GetMapping("/getByIds")
    public JsonResult<E> getByIds(@RequestParam(value = "ids") String ids) {
        JsonResult result = JsonResult.Success();
        result.setShow(false);
        if (ObjectUtils.isEmpty(ids)) {
            return result.setData(new Object());
        }
        String[] aryId = ids.split(",");
        List<String> idList = Arrays.asList(aryId);
        List<E> byIds = getBaseService().getByIds(idList);
        return result.setData(byIds);
    }

}
